// Extend.js (http://code.google.com/p/extendjs/)
// Copyright 2010 Shumpei Shiraishi All rights reserved.
// Licensed under the MIT license.

(function(_global) {
    var NATIVE_METHODS_FUNCTION = [
	"toString", "apply", "call", "bind"
    ];
    var slice = Array.prototype.slice;
    function update(array, args) {
	var arrayLength = array.length, length = args.length;
	while (length--) array[arrayLength + length] = args[length];
	return array;
    }
    function merge(array, args) {
	array = slice.call(array, 0);
	return update(array, args);
    }
    X.extend("Function", function(value) {
	return typeof value === "function";
    });
    X.Function.extend({
	isFunction: function() {
	    return true;
	},
	bind: function(context) {
	    if (arguments.length < 2 && arguments[0] === undefined) return this.__val;
	    var __method = this.__val, args = slice.call(arguments, 1);
	    return function() {
		var a = merge(args, arguments);
		return __method.apply(context, a);
	    }
	},
	argumentNames: function() {
	    var names = this.__val.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
	    .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
	    .replace(/\s+/g, '').split(',');
	    return names.length == 1 && !names[0] ? [] : names;
	},
	curry: function() {
	    if (!arguments.length) return this.__val;
	    var __method = this.__val, args = slice.call(arguments, 0);
	    return function() {
		var a = merge(args, arguments);
		return __method.apply(this, a);
	    }
	},
	delay: function(timeout) {
	    var __method = this.__val, args = slice.call(arguments, 1);
	    return setTimeout(function() {
		return __method.apply(__method, args);
	    }, timeout);
	},
	defer: function() {
	    var args = update([0.01], arguments);
	    return this.delay.apply(this, args);
	},
	wrap: function(wrapper) {
	    var __method = this.__val;
	    return function() {
		var a = update([__method.bind(this)], arguments);
		return wrapper.apply(this, a);
	    }
	},
	length: function() {
	    return this.__val.length;
	}
    });
    X.Function.mixin(Function.prototype, NATIVE_METHODS_FUNCTION);
})(this);
